package org.ytor.core.sqlflow.executor;

import org.ytor.common.exception.BaseException;
import org.ytor.core.sqlflow.executor.ds.DataSourceManager;
import org.ytor.core.sqlflow.log.SqlLogHelper;

import java.sql.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * created by yangtong on 2025/8/8 18:12:34
 * <br/>
 * SQL 执行器
 */
public class JdbcSqlExecutor implements SqlExecutor {

    /**
     * 数据源
     */
    private final DataSourceManager dataSourceManager;

    public JdbcSqlExecutor(DataSourceManager dataSourceManager) {
        this.dataSourceManager = dataSourceManager;
    }

    @Override
    public DQLResult doQuery(String sql, List<Object> params) {
        long start = System.currentTimeMillis();

        // 获取数据库连接
        Connection conn = dataSourceManager.get();
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            bind(ps, params);
            try (ResultSet rs = ps.executeQuery()) {
                // 结束查询
                long end = System.currentTimeMillis();
                DQLResult result = DQLResult.parseResultSet(rs);

                result.setSql(sql);
                result.setExecutedSql(sqlWithParams(sql, params));
                // SQL 查询耗时
                result.setSqlCostMillis(end - start);
                return result;
            }
        } catch (SQLException e) {
            SqlLogHelper.error("查询出错!", e);
            throw new BaseException(e);
        } finally {
            dataSourceManager.close(conn);
        }
    }

    @Override
    public DMLResult doInsert(String sql, List<Object> params) {
        DMLResult dmlResult = new DMLResult();
        dmlResult.setType("INSERT");

        long start = System.currentTimeMillis();
        // 获取数据库连接
        Connection conn = dataSourceManager.get();
        try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
            bind(ps, params);

            // 执行SQL，并返回影响行数
            int rowAffected = ps.executeUpdate();

            dmlResult.setRowAffected(rowAffected);
            dmlResult.setSql(sql);
            dmlResult.setExecutedSql(sqlWithParams(sql, params));
            dmlResult.setSqlCostMillis(System.currentTimeMillis() - start);

            // 获取生成的主键
            try (ResultSet rs = ps.getGeneratedKeys()) {
                if (rs.next()) {
                    dmlResult.setId(rs.getString(1));
                }
            }

            return dmlResult;
        } catch (SQLException e) {
            SqlLogHelper.error("插入数据出错!", e);
            throw new BaseException(e);
        } finally {
            dataSourceManager.close(conn);
        }
    }

    @Override
    public List<DMLResult> doInsertBatch(String sql, List<List<Object>> batchParams) {
        if (batchParams == null || batchParams.isEmpty())
            return Collections.emptyList();
        if (batchParams.size() > 1000)
            throw new IllegalArgumentException("一次性提交的数据不能超过1000，当前数据量：" + batchParams.size());

        long start = System.currentTimeMillis();

        // 获取数据库连接
        Connection conn = dataSourceManager.get();
        try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {

            try {
                // 1) 组装 batch
                for (List<Object> params : batchParams) {
                    bind(ps, params);
                    ps.addBatch();
                }

                // 2) 执行 batch
                int[] counts = ps.executeBatch();

                long cost = System.currentTimeMillis() - start;

                // 3) 批量主键
                List<String> ids;
                ids = new ArrayList<>();
                try (ResultSet rs = ps.getGeneratedKeys()) {
                    while (rs != null && rs.next()) {
                        Object k = rs.getObject(1);
                        ids.add(k == null ? null : String.valueOf(k));
                    }
                } catch (SQLException ignore) {
                    // 某些驱动不支持批量主键；忽略即可
                }

                // 4) 组装返回结果（长度与 batchParams 一致）
                List<DMLResult> results = new ArrayList<>(counts.length);
                for (int i = 0; i < counts.length; i++) {
                    DMLResult dmlResult = new DMLResult();
                    dmlResult.setType("INSERT");
                    int c = counts[i];
                    // JDBC 可能返回 -2(SUCCESS_NO_INFO)/-3(EXECUTE_FAILED)；这里将负数归 0
                    dmlResult.setRowAffected(Math.max(c, 0));
                    if (i < ids.size()) {
                        dmlResult.setId(ids.get(i));
                    }
                    dmlResult.setSql(sql);
                    dmlResult.setExecutedSql(sqlWithParams(sql, batchParams.get(i)));
                    dmlResult.setSqlCostMillis(cost);
                    results.add(i, dmlResult);
                }

                return results;
            } catch (SQLException e) {
                SqlLogHelper.error("批量插入出错,进行回滚", e);
                throw new BaseException("doInsertBatch 执行失败: " + sql, e);
            }
        } catch (SQLException e) {
            SqlLogHelper.error("批量插入获取连接失败!", e);
            throw new BaseException("doInsertBatch 获取连接失败: " + sql, e);
        } finally {
            dataSourceManager.close(conn);
        }
    }

    @Override
    public DMLResult doDelete(String sql, List<Object> params) {
        DMLResult dmlResult = new DMLResult();
        dmlResult.setType("DELETE");

        long start = System.currentTimeMillis();
        // 获取数据库连接
        Connection conn = dataSourceManager.get();
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            bind(ps, params);

            // 执行SQL，并返回影响行数
            int rowAffected = ps.executeUpdate();

            dmlResult.setRowAffected(rowAffected);
            dmlResult.setSql(sql);
            dmlResult.setExecutedSql(sqlWithParams(sql, params));
            dmlResult.setSqlCostMillis(System.currentTimeMillis() - start);

            return dmlResult;
        } catch (SQLException e) {
            SqlLogHelper.error("删除数据出错!", e);
            throw new BaseException(e);
        } finally {
            dataSourceManager.close(conn);
        }
    }

    @Override
    public DMLResult doUpdate(String sql, List<Object> params) {
        DMLResult dmlResult = new DMLResult();
        dmlResult.setType("UPDATE");

        long start = System.currentTimeMillis();
        // 获取数据库连接
        Connection conn = dataSourceManager.get();
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            bind(ps, params);

            // 执行SQL，并返回影响行数
            int rowAffected = ps.executeUpdate();

            dmlResult.setRowAffected(rowAffected);
            dmlResult.setSql(sql);
            dmlResult.setExecutedSql(sqlWithParams(sql, params));
            dmlResult.setSqlCostMillis(System.currentTimeMillis() - start);

            return dmlResult;
        } catch (SQLException e) {
            SqlLogHelper.error("更新数据出错!", e);
            throw new BaseException(e);
        } finally {
            dataSourceManager.close(conn);
        }
    }

    @Override
    public DMLResult doDDL(String sql, List<Object> params) {
        return null;
    }

    /**
     * 给SQL 占位符绑定参数
     */
    private void bind(PreparedStatement ps, List<Object> params) throws SQLException {
        if (params == null) return;
        for (int i = 0; i < params.size(); i++) ps.setObject(i + 1, params.get(i));
    }

    private String sqlWithParams(String sql, List<Object> params) {
        // TODO: 实现SQL参数替换逻辑
        return null;
    }
}